import random
from collections import defaultdict


class City:
    """城池类"""

    def __init__(self, name, population, agriculture, commerce, defense, lord=None):
        self.name = name  # 城池名称
        self.population = population  # 人口（单位：万）
        self.agriculture = agriculture  # 农业值
        self.commerce = commerce  # 商业值
        self.defense = defense  # 城防值
        self.lord = lord  # 所属君主
        self.garrison = 0  # 驻军数量
        self.gold = 1000  # 城池金钱

    def __str__(self):
        return (f"{self.name} (人口: {self.population}万, 农业: {self.agriculture}, "
                f"商业: {self.commerce}, 城防: {self.defense}, "
                f"驻军: {self.garrison}, 金钱: {self.gold}, "
                f"君主: {self.lord.name if self.lord else '无'})")


class General:
    """武将类"""

    def __init__(self, name, strength, intelligence, leadership, lord=None):
        self.name = name  # 武将姓名
        self.strength = strength  # 武力
        self.intelligence = intelligence  # 智力
        self.leadership = leadership  # 统率
        self.lord = lord  # 所属君主
        self.city = None  # 所在城池
        self.troops = 0  # 统率兵力

    def __str__(self):
        return (f"{self.name} (武力: {self.strength}, 智力: {self.intelligence}, "
                f"统率: {self.leadership}, 兵力: {self.troops}, "
                f"君主: {self.lord.name if self.lord else '无'}, "
                f"位置: {self.city.name if self.city else '无'})")


class Lord:
    """君主类"""

    def __init__(self, name, gold=5000, action_points=100):
        self.name = name  # 君主姓名
        self.gold = gold  # 金钱
        self.action_points = action_points  # 行动力
        self.cities = []  # 拥有的城池
        self.generals = []  # 拥有的武将
        self.available_actions = 100  # 当前可用行动力

    def __str__(self):
        return (f"{self.name} (金钱: {self.gold}, 行动力: {self.available_actions}/{self.action_points}, "
                f"城池: {len(self.cities)}, 武将: {len(self.generals)})")

    def reset_actions(self):
        """重置行动力"""
        self.available_actions = self.action_points


class Game:
    """游戏主类"""

    def __init__(self):
        self.lords = []  # 所有君主
        self.cities = []  # 所有城池
        self.generals = []  # 所有武将
        self.current_turn = 0  # 当前回合
        self.player = None  # 玩家控制的君主

    def initialize_game(self):
        """初始化游戏数据"""
        # 创建君主
        player = Lord("刘备", gold=8000)
        self.player = player
        self.lords.append(player)
        self.lords.append(Lord("曹操"))
        self.lords.append(Lord("孙权"))
        self.lords.append(Lord("董卓"))

        # 创建城池
        cities_data = [
            ("洛阳", 120, 80, 90, 100, self.lords[3]),
            ("长安", 100, 70, 80, 90, self.lords[3]),
            ("许昌", 90, 75, 85, 80, self.lords[1]),
            ("邺城", 85, 70, 75, 85, self.lords[1]),
            ("建业", 95, 65, 90, 75, self.lords[2]),
            ("成都", 80, 85, 70, 85, None),
            ("襄阳", 75, 75, 80, 70, None),
            ("江陵", 70, 60, 75, 65, None),
            ("新野", 60, 65, 60, 50, player),
            ("小沛", 55, 60, 55, 45, player)
        ]

        for data in cities_data:
            city = City(*data)
            self.cities.append(city)
            if city.lord:
                city.lord.cities.append(city)
                city.garrison = random.randint(5000, 10000)  # 初始驻军

        # 创建武将
        generals_data = [
            # 玩家武将
            ("关羽", 95, 85, 92, player),
            ("张飞", 90, 60, 85, player),
            ("赵云", 92, 80, 90, player),
            ("诸葛亮", 65, 98, 90, player),
            # 曹操武将
            ("夏侯惇", 88, 70, 85, self.lords[1]),
            ("典韦", 95, 45, 75, self.lords[1]),
            ("郭嘉", 60, 95, 80, self.lords[1]),
            # 孙权武将
            ("周瑜", 85, 95, 90, self.lords[2]),
            ("黄盖", 85, 70, 80, self.lords[2]),
            ("鲁肃", 65, 90, 85, self.lords[2]),
            # 董卓武将
            ("吕布", 100, 40, 85, self.lords[3]),
            ("华雄", 90, 55, 80, self.lords[3]),
            ("李儒", 50, 90, 75, self.lords[3]),
            # 在野武将
            ("徐庶", 70, 92, 80, None),
            ("庞统", 65, 95, 85, None),
            ("甘宁", 92, 75, 88, None)
        ]

        for data in generals_data:
            general = General(*data)
            self.generals.append(general)
            if general.lord:
                general.lord.generals.append(general)
                # 分配初始兵力
                general.troops = random.randint(3000, 8000)
                # 分配到随机城池
                if general.lord.cities:
                    city = random.choice(general.lord.cities)
                    general.city = city
                    city.garrison += general.troops

        # 分配玩家武将到城池
        player_cities = player.cities
        if player_cities:
            for general in player.generals:
                city = random.choice(player_cities)
                general.city = city
                city.garrison += general.troops

    def collect_taxes(self):
        """所有君主征收税收"""
        for lord in self.lords:
            tax_income = 0
            for city in lord.cities:
                # 税收 = 人口 * (商业值/100) * 0.1
                tax = int(city.population * (city.commerce / 100) * 0.1)
                city.gold -= tax
                tax_income += tax
            lord.gold += tax_income

    def display_game_state(self):
        """显示当前游戏状态"""
        print(f"\n===== 第 {self.current_turn} 回合 =====")
        print(f"玩家: {self.player}")

        print("\n【玩家城池】")
        for city in self.player.cities:
            print(f"- {city}")

        print("\n【玩家武将】")
        for general in self.player.generals:
            print(f"- {general}")

        print("\n【其他势力】")
        for lord in self.lords:
            if lord != self.player:
                print(f"- {lord.name}: 城池 {len(lord.cities)}座, 武将 {len(lord.generals)}名")

        print(f"\n可用行动力: {self.player.available_actions}")

    def display_actions(self):
        """显示可用的行动菜单"""
        print("\n===== 行动菜单 =====")
        actions = [
            ("1", "发展农业 (消耗20行动力)", self.develop_agriculture),
            ("2", "发展商业 (消耗20行动力)", self.develop_commerce),
            ("3", "招募士兵 (消耗30行动力)", self.recruit_troops),
            ("4", "训练士兵 (消耗25行动力)", self.train_troops),
            ("5", "移动武将 (消耗15行动力)", self.move_general),
            ("6", "探索人才 (消耗40行动力)", self.search_generals),
            ("7", "出征 (消耗50行动力)", self.launch_attack),
            ("8", "结束回合", self.end_turn),
            ("9", "查看游戏状态", self.display_game_state),
            ("0", "退出游戏", exit)
        ]

        for action in actions:
            print(f"{action[0]}. {action[1]}")

    def develop_agriculture(self):
        """发展农业"""
        if self.player.available_actions < 20:
            print("行动力不足！")
            return False

        print("\n【发展农业】")
        print("选择要发展的城池：")
        for i, city in enumerate(self.player.cities):
            print(f"{i + 1}. {city.name} (农业: {city.agriculture})")

        try:
            choice = int(input("请输入选择: ")) - 1
            if 0 <= choice < len(self.player.cities):
                city = self.player.cities[choice]
                increase = random.randint(3, 8)
                city.agriculture += increase
                self.player.available_actions -= 20
                print(f"{city.name} 农业发展成功！农业值增加 {increase}，当前农业值: {city.agriculture}")
                return True
            else:
                print("无效选择！")
                return False
        except ValueError:
            print("无效输入！")
            return False

    def develop_commerce(self):
        """发展商业"""
        if self.player.available_actions < 20:
            print("行动力不足！")
            return False

        print("\n【发展商业】")
        print("选择要发展的城池：")
        for i, city in enumerate(self.player.cities):
            print(f"{i + 1}. {city.name} (商业: {city.commerce})")

        try:
            choice = int(input("请输入选择: ")) - 1
            if 0 <= choice < len(self.player.cities):
                city = self.player.cities[choice]
                increase = random.randint(3, 8)
                city.commerce += increase
                self.player.available_actions -= 20
                print(f"{city.name} 商业发展成功！商业值增加 {increase}，当前商业值: {city.commerce}")
                return True
            else:
                print("无效选择！")
                return False
        except ValueError:
            print("无效输入！")
            return False

    def recruit_troops(self):
        """招募士兵"""
        if self.player.available_actions < 30:
            print("行动力不足！")
            return False

        print("\n【招募士兵】")
        print("选择招募城池：")
        for i, city in enumerate(self.player.cities):
            print(f"{i + 1}. {city.name} (人口: {city.population}万, 金钱: {city.gold})")

        try:
            choice = int(input("请输入选择: ")) - 1
            if 0 <= choice < len(self.player.cities):
                city = self.player.cities[choice]
                max_recruit = min(city.population * 100, city.gold // 10)  # 每名士兵10金
                if max_recruit <= 0:
                    print("人口或金钱不足，无法招募士兵！")
                    return False

                troops = int(input(f"请输入招募数量 (最大 {max_recruit}): "))
                if troops <= 0 or troops > max_recruit:
                    print("招募数量无效！")
                    return False

                cost = troops * 10
                city.gold -= cost
                city.garrison += troops
                self.player.available_actions -= 30
                print(f"成功招募 {troops} 名士兵！消耗金钱 {cost}，{city.name} 驻军增加至 {city.garrison}")
                return True
            else:
                print("无效选择！")
                return False
        except ValueError:
            print("无效输入！")
            return False

    def train_troops(self):
        """训练士兵"""
        if self.player.available_actions < 25:
            print("行动力不足！")
            return False

        print("\n【训练士兵】")
        print("选择要训练的武将：")
        for i, general in enumerate(self.player.generals):
            print(f"{i + 1}. {general.name} (统率: {general.leadership}, 兵力: {general.troops})")

        try:
            choice = int(input("请输入选择: ")) - 1
            if 0 <= choice < len(self.player.generals):
                general = self.player.generals[choice]
                if general.troops == 0:
                    print("该武将没有士兵可训练！")
                    return False

                # 训练效果取决于武将的统率
                effectiveness = general.leadership / 100
                increase = int(general.troops * effectiveness * random.uniform(0.1, 0.2))
                general.troops += increase
                city = general.city
                if city:  # 确保武将所在城池存在
                    city.garrison += increase
                self.player.available_actions -= 25
                print(f"{general.name} 训练士兵成功！兵力增加 {increase}，当前兵力: {general.troops}")
                return True
            else:
                print("无效选择！")
                return False
        except ValueError:
            print("无效输入！")
            return False

    def move_general(self):
        """移动武将"""
        if self.player.available_actions < 15:
            print("行动力不足！")
            return False

        print("\n【移动武将】")
        print("选择要移动的武将：")
        for i, general in enumerate(self.player.generals):
            print(f"{i + 1}. {general.name} (位置: {general.city.name if general.city else '无'})")

        try:
            gen_choice = int(input("请输入选择: ")) - 1
            if gen_choice < 0 or gen_choice >= len(self.player.generals):
                print("无效选择！")
                return False

            general = self.player.generals[gen_choice]
            current_city = general.city

            print("\n选择目标城池：")
            player_cities = self.player.cities
            for i, city in enumerate(player_cities):
                if city != current_city:
                    print(f"{i + 1}. {city.name}")

            if len(player_cities) <= 1:
                print("没有其他城池可移动！")
                return False

            city_choice = int(input("请输入选择: ")) - 1
            if city_choice < 0 or city_choice >= len(player_cities):
                print("无效选择！")
                return False

            target_city = player_cities[city_choice]
            if target_city == current_city:
                print("武将已在此城池！")
                return False

            # 移动武将
            if current_city:
                current_city.garrison -= general.troops
            general.city = target_city
            target_city.garrison += general.troops
            self.player.available_actions -= 15
            print(f"{general.name} 已从 {current_city.name if current_city else '无'} 移动到 {target_city.name}")
            return True
        except ValueError:
            print("无效输入！")
            return False

    def search_generals(self):
        """探索人才"""
        if self.player.available_actions < 40:
            print("行动力不足！")
            return False

        print("\n【探索人才】")
        # 获取在野武将
        available_generals = [g for g in self.generals if g.lord is None]
        if not available_generals:
            print("当前没有在野武将！")
            return False

        # 随机选择一个在野武将
        general = random.choice(available_generals)

        # 探索成功率取决于玩家实力
        success_rate = min(0.3 + len(self.player.cities) * 0.1, 0.8)
        success = random.random() < success_rate

        self.player.available_actions -= 40

        if success:
            # 招募成功
            general.lord = self.player
            self.player.generals.append(general)
            # 分配到随机城池
            if self.player.cities:
                city = random.choice(self.player.cities)
                general.city = city
                city.garrison += general.troops
            print(
                f"探索成功！发现了 {general.name} (武力: {general.strength}, 智力: {general.intelligence}) 并成功招募！")
        else:
            print("探索失败，没有发现人才。")

        return True

    def launch_attack(self):
        """出征攻击其他城池"""
        if self.player.available_actions < 50:
            print("行动力不足！")
            return False

        print("\n【出征】")
        # 选择进攻的武将
        print("选择进攻的武将：")
        available_generals = [g for g in self.player.generals if g.troops > 0]
        if not available_generals:
            print("没有可用的武将！")
            return False

        for i, general in enumerate(available_generals):
            print(f"{i + 1}. {general.name} (兵力: {general.troops}, 位置: {general.city.name})")

        try:
            gen_choice = int(input("请输入选择: ")) - 1
            if gen_choice < 0 or gen_choice >= len(available_generals):
                print("无效选择！")
                return False

            attacker = available_generals[gen_choice]

            # 选择目标城池
            print("\n选择目标城池：")
            # 获取可以攻击的城池（非玩家城池）
            target_cities = [c for c in self.cities if c.lord != self.player]
            if not target_cities:
                print("没有可攻击的目标城池！")
                return False

            for i, city in enumerate(target_cities):
                print(
                    f"{i + 1}. {city.name} (君主: {city.lord.name if city.lord else '无'}, 城防: {city.defense}, 驻军: {city.garrison})")

            city_choice = int(input("请输入选择: ")) - 1
            if city_choice < 0 or city_choice >= len(target_cities):
                print("无效选择！")
                return False

            target_city = target_cities[city_choice]

            # 开始战斗
            print(f"\n{attacker.name} 率领 {attacker.troops} 名士兵向 {target_city.name} 发起进攻！")

            # 计算攻击力
            attack_power = attacker.troops * (attacker.strength + attacker.leadership) / 200
            # 计算防御力
            defense_power = target_city.garrison * (target_city.defense / 100)

            # 战斗结果
            if attack_power > defense_power * 1.5:
                # 大胜
                result = "大胜"
                attacker_loss = int(attacker.troops * random.uniform(0.1, 0.2))
                defender_loss = target_city.garrison
                captured = True
            elif attack_power > defense_power:
                # 胜利
                result = "胜利"
                attacker_loss = int(attacker.troops * random.uniform(0.2, 0.4))
                defender_loss = int(target_city.garrison * random.uniform(0.8, 1.0))
                captured = True
            elif attack_power > defense_power * 0.7:
                # 惨胜
                result = "惨胜"
                attacker_loss = int(attacker.troops * random.uniform(0.4, 0.6))
                defender_loss = int(target_city.garrison * random.uniform(0.6, 0.8))
                captured = True
            else:
                # 失败
                result = "失败"
                attacker_loss = int(attacker.troops * random.uniform(0.6, 0.8))
                defender_loss = int(target_city.garrison * random.uniform(0.2, 0.4))
                captured = False

            # 更新兵力
            attacker.troops -= attacker_loss
            if attacker.troops < 0:
                attacker.troops = 0

            target_city.garrison -= defender_loss
            if target_city.garrison < 0:
                target_city.garrison = 0

            # 更新城池驻军
            if attacker.city:
                attacker.city.garrison -= attacker_loss

            print(f"战斗结果: {result}!")
            print(f"我方损失: {attacker_loss}名士兵, 剩余兵力: {attacker.troops}")
            print(f"守军损失: {defender_loss}名士兵, 剩余守军: {target_city.garrison}")

            if captured:
                # 占领城池
                original_lord = target_city.lord
                if original_lord:
                    original_lord.cities.remove(target_city)
                target_city.lord = self.player
                self.player.cities.append(target_city)
                print(f"成功占领 {target_city.name}！")

                # 获取城池部分金钱
                captured_gold = int(target_city.gold * 0.7)
                self.player.gold += captured_gold
                target_city.gold -= captured_gold
                print(f"缴获 {captured_gold} 金钱！")
            else:
                print("未能攻占城池。")

            self.player.available_actions -= 50
            return True
        except ValueError:
            print("无效输入！")
            return False

    def end_turn(self):
        """结束当前回合"""
        print("\n===== 回合结束 =====")

        # 征收税收
        self.collect_taxes()
        print("已征收税收")

        # 其他君主的行动
        print("\n【其他势力行动】")
        for lord in self.lords:
            if lord != self.player:
                # 随机发展
                if lord.cities and random.random() > 0.3:
                    city = random.choice(lord.cities)
                    if random.random() > 0.5:
                        city.agriculture += random.randint(2, 5)
                        print(f"{lord.name} 在 {city.name} 发展农业 (农业+{city.agriculture})")
                    else:
                        city.commerce += random.randint(2, 5)
                        print(f"{lord.name} 在 {city.name} 发展商业 (商业+{city.commerce})")

                # 随机招募士兵
                if lord.cities and random.random() > 0.4:
                    city = random.choice(lord.cities)
                    if city.gold > 1000 and city.population > 30:
                        troops = random.randint(1000, 5000)
                        cost = troops * 10
                        city.gold -= cost
                        city.garrison += troops
                        print(f"{lord.name} 在 {city.name} 招募了 {troops} 名士兵")

        # 回合数增加
        self.current_turn += 1

        # 重置玩家行动力
        self.player.reset_actions()
        print(f"\n第 {self.current_turn} 回合开始！")

        # 随机事件
        if random.random() < 0.3:
            self.random_event()

        return True

    def random_event(self):
        """随机事件"""

        # 定义事件效果函数
        def increase_agriculture():
            for city in self.player.cities:
                city.agriculture += 5
            print("所有城池农业值增加5点！")

        def increase_commerce():
            for city in self.player.cities:
                city.commerce += 5
            print("所有城池商业值增加5点！")

        def add_treasure():
            if self.player.cities:
                city = random.choice(self.player.cities)
                bonus = random.randint(1000, 3000)
                city.gold += bonus
                print(f"在{city.name}发现宝藏，获得{bonus}金钱！")

        def plague_outbreak():
            for city in self.player.cities:
                reduction = random.randint(1, 5)
                city.population = max(10, city.population - reduction)
            print("所有城池人口减少1-5万！")

        def add_random_general():
            available_generals = [g for g in self.generals if g.lord is None]
            if available_generals:
                general = random.choice(available_generals)
                general.lord = self.player
                self.player.generals.append(general)
                if self.player.cities:
                    city = random.choice(self.player.cities)
                    general.city = city
                    city.garrison += general.troops
                print(f"{general.name} 加入了你的势力！")
            else:
                print("没有在野武将可加入。")

        # 事件列表
        events = [
            ("丰收之年", "风调雨顺，农业大丰收！所有城池农业值增加5点。", increase_agriculture),
            ("商业繁荣", "商路畅通，商业繁荣！所有城池商业值增加5点。", increase_commerce),
            ("发现宝藏", "在城池中发现了一个隐藏的宝藏！", add_treasure),
            ("瘟疫流行", "瘟疫流行，人口减少！", plague_outbreak),
            ("武将忠诚", "一位在野武将慕名而来，请求加入！", add_random_general)
        ]

        event = random.choice(events)
        print(f"\n【随机事件】{event[0]}")
        print(event[1])
        event[2]()  # 执行事件效果

    def main_loop(self):
        """游戏主循环"""
        print("===== 三国回合制策略游戏 =====")
        print("你是刘备，拥有新野和小沛两座城池")
        print("目标：发展势力，统一天下！")

        self.initialize_game()
        self.display_game_state()

        while True:
            self.display_actions()
            choice = input("\n请输入行动编号: ")

            actions = {
                "1": self.develop_agriculture,
                "2": self.develop_commerce,
                "3": self.recruit_troops,
                "4": self.train_troops,
                "5": self.move_general,
                "6": self.search_generals,
                "7": self.launch_attack,
                "8": self.end_turn,
                "9": self.display_game_state,
                "0": exit
            }

            if choice in actions:
                if choice == "0":
                    print("游戏结束，再见！")
                    break
                actions[choice]()
            else:
                print("无效选择，请重新输入！")


# 启动游戏
if __name__ == "__main__":
    game = Game()
    game.main_loop()